package com.open.config;

import javax.sql.DataSource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
import org.springframework.security.oauth2.provider.token.ResourceServerTokenServices;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JdbcTokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;

@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {

	// 配置资源id ,对应oauth_client_details表中配置的resourceIds
	// 一个资源ID可以对应一个资源服务器，如果Token中不包含该资源ID就无法访问该资源服务器
	private static final String RESOURCE_ID = "order-service";

	@Autowired
	private DataSource dataSource;

	@Autowired
	private RedisConnectionFactory redisConnectionFactory;
	
	/**
	 * 签名key
	 */
	private String signingKey = "jwt_123qbc";

	/**
	 * 创建一个默认的资源服务token
	 *
	 * @return
	 */
	@Bean
	public ResourceServerTokenServices defaultTokenServices() {
		final DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
		defaultTokenServices.setTokenEnhancer(accessTokenConverter());
		defaultTokenServices.setTokenStore(tokenStore());
		return defaultTokenServices;
	}
	
	/**
	 * https://blog.csdn.net/qq_47200599/article/details/108568617
	 * 
	 * 资源服务配置
	 * 
	 * @param resources
	 * @throws Exception
	 */
	@Override
	public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
		resources.resourceId(RESOURCE_ID).tokenStore(tokenStore()) // jwt令牌验证
				.tokenServices(defaultTokenServices())
				// .tokenServices(this.tokenService())//验证令牌的服务，令牌校验的方式，远程校验：RemoteTokenServices
				// 同个工程本地校验：DefaultTokenServices
				// .authenticationEntryPoint(new XXXX) //自定义返回信息
				// .accessDeniedHandler(new AccessDeniedHandler()) /自定义返回信息
				.stateless(true);
	}

	@Override
	public void configure(HttpSecurity http) throws Exception {
		// 全部需要认证
		http.authorizeRequests()
				.anyRequest()
				.authenticated()
				.and()
				.csrf()
				.disable() // 去除csrf攻击的配置，以便除get请求方式，其他请求方式也能访问接口
				.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);// 因为是基于token的验证
																							// 那么这里配置session就不用再记录了
	}

	@Bean
	public TokenStore tokenStore() {
		// TokenStore redisTokenStore = new RedisTokenStore(redisConnectionFactory);
		TokenStore jdbcTokenStore = new JdbcTokenStore(dataSource);
		return jdbcTokenStore;
	}

	/**
	 * Token转换器必须与认证服务一致
	 *
	 * @return
	 */
	@Bean
	public JwtAccessTokenConverter accessTokenConverter() {
		JwtAccessTokenConverter accessTokenConverter = new JwtAccessTokenConverter();
		// 资源服务使用相同的字符达到一个对称加密的效果,生产时候使用RSA非对称加密方式
		accessTokenConverter.setSigningKey(signingKey);
		return accessTokenConverter;
	}
}
